package com.ganyu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ganyu.component.RedisCache;
import com.ganyu.constant.SystemConstant;
import com.ganyu.domain.ResponseResult;
import com.ganyu.domain.dto.AddArticleDto;
import com.ganyu.domain.dto.UpdateAdminArticleDto;
import com.ganyu.domain.entity.Article;
import com.ganyu.domain.entity.ArticleTag;
import com.ganyu.domain.entity.Category;
import com.ganyu.domain.vo.*;
import com.ganyu.mapper.ArticleMapper;
import com.ganyu.mapper.ArticleTagMapper;
import com.ganyu.mapper.CategoryMapper;
import com.ganyu.mapper.TagMapper;
import com.ganyu.service.ArticleService;
import com.ganyu.service.ArticleTagService;
import com.ganyu.service.CategoryService;
import com.ganyu.utils.BeanCopyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.ganyu.constant.SystemConstant.ARTICLE_STATUS_NORMAL;
import static com.ganyu.constant.SystemConstant.INCREASE;


@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private ArticleService articleService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ArticleTagMapper articleTagMapper;
    
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private TagMapper tagMapper;
    /**
     * 查询热门文章
     */
    @Override
    public ResponseResult<HotArticleVo> getHotArticle() {
        //1. 查询正式的文章，正式文章：字段 status = 0
        //1.1 使用MybatisPlus进行查询并判断(查询出status = 0的文章)
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getStatus, ARTICLE_STATUS_NORMAL);
        //1.2 根据浏览量降序排序，浏览量：字段 view_count
        queryWrapper.orderByDesc(Article::getViewCount);
        //1.3展示前10篇文章
        Page<Article> page = new Page<>(SystemConstant.ARTICLE_PAGE_NUMBER,SystemConstant.ARTICLE_NUMBER);
        page(page,queryWrapper);
        List<Article> articles = page.getRecords();
        //1.4返回需要返回的字段(bean拷贝)
        List<HotArticleVo> hotArticleVos = BeanCopyUtils.copyBeanList(articles, HotArticleVo.class);
        //2.获取文章数量
        int articleCount = articleMapper.selectArticleCount();
        //获取分类数量
        int categoryCount = categoryMapper.selectCategoryCount();
        //获取标签数量
        int tagCount = tagMapper.selectTagCount();
        for(HotArticleVo hotArticle : hotArticleVos){
            hotArticle.setArticleCount(articleCount);
            hotArticle.setCategoryCount(categoryCount);
            hotArticle.setTagCount(tagCount);
        }
        return ResponseResult.okResult(hotArticleVos);
    }

    /**
     * 首页文章显示和分类文章显示
     */
    @Override
    public ResponseResult<PageVo> getArticleList(Integer pageNum, Integer pageSize, Long categoryId) {
        //1. 查询文章，分首页（没有categoryId）和文章列表（有categoryId）
        LambdaQueryWrapper<Article> articleQuery = new LambdaQueryWrapper<>();
        //1.1 有文章列表的情况（categoryId不为空或大于0）
        articleQuery.eq(Objects.nonNull(categoryId) && categoryId > 0,Article::getCategoryId,categoryId);
        //2. 查询正式的文章
        articleQuery.eq(Article::getStatus,ARTICLE_STATUS_NORMAL);
        //3. 置顶文章显示在最前面
        articleQuery.orderByDesc(Article::getIsTop);
        //4. 进行分页操作
        Page<Article> page = new Page<>(pageNum,pageSize);
        page(page,articleQuery);
        List<Article> articles = page.getRecords();
        //stream流
        articles.stream()
                .map(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()))
                .collect(Collectors.toList());
        //5. 返回需要返回的类型（bean拷贝）
        List<ArticleListVo> articleListVos = BeanCopyUtils.copyBeanList(articles, ArticleListVo.class);
        //6.查询文章浏览量从reids中获取
        for(ArticleListVo articleListVo : articleListVos){
           Integer cacheMapValue = redisCache.getCacheMapValue("article:viewCount", articleListVo.getId().toString());
            if(ObjectUtils.isEmpty(cacheMapValue)){
                //向redis中插入新的浏览量
                redisCache.setCacheMapValue("article:viewCount",articleListVo.getId().toString(),articleListVo.getViewCount().intValue());
            }
            Integer articleView = redisCache.getCacheMapValue("article:viewCount", articleListVo.getId().toString());
            articleListVo.setViewCount(articleView.longValue());
        }
        PageVo<ArticleListVo> pageVo = new PageVo<>();
        pageVo.setRows(articleListVos);
        pageVo.setTotal((int)page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    /**
     * 文章详情
     */
    @Override
    public ResponseResult<ArticleDetailVo> getArticleDetail(Long id) {
        //1. 根据id去查询文章
        Article article = articleService.getById(id);
        //1.1 查询文章浏览量从reids中获取
        //判断redis中是否能获取浏览量，添加文章时redis中是没有新文章的浏览量的
        Integer cacheMapValue = redisCache.getCacheMapValue("article:viewCount", id.toString());
        if(ObjectUtils.isEmpty(cacheMapValue)){
            //向redis中插入新的浏览量
            redisCache.setCacheMapValue("article:viewCount",id.toString(),article.getViewCount().intValue());
        }
        //再次从redis中查询
        Integer articleView = redisCache.getCacheMapValue("article:viewCount", id.toString());
        article.setViewCount(articleView.longValue());
        //1.2 根据id查询Article表中的catetoryId，然后在Catetory表中获取catetoryName
        Long categoryId = article.getCategoryId();
        //1.3 防止报空指针异常，有文章分类就显示，没有就不显示
        if(categoryId != null){
            Category category = categoryService.getById(categoryId);
            article.setCategoryName(category.getName());
        }
        //2. 返回需要返回的类型（bean拷贝）
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        return ResponseResult.okResult(articleDetailVo);
    }

    /**
     * 更新redis中的浏览记录
     */
    @Override
    public ResponseResult updateView(Long id) {
        //每点击一次redis，就增加一次
        redisCache.incrementCacheMapValue("article:viewCount",id.toString(),INCREASE);
        return ResponseResult.okResult();
    }

    /**
     * 添加文章
     */
    @Override
    @Transactional //出现异常保持回滚
    public ResponseResult add(AddArticleDto article) {
        //将article转为Article类型
        Article article1 = BeanCopyUtils.copyBean(article, Article.class);
        //进行插入
        save(article1);

        //获取article的id获取tag_id中的标签集合
        List<Long> tags = article.getTags();
        //遍历tags，并插入到数据库中
        for(Long tag :tags){
            articleTagMapper.insert(article.getId(),tag);
        }
        return ResponseResult.okResult();
    }

    //文章模糊查询
    @Override
    public ResponseResult getArticleFuzzy(Integer pageNum, Integer pageSize, String title, String summary) {
        Integer num = (pageNum - 1) * pageSize;
        List<Article> articleFuzzy = articleMapper.getArticleFuzzy(num, pageSize, title, summary);
        List<AdminArticleVo> adminArticleVos = BeanCopyUtils.copyBeanList(articleFuzzy, AdminArticleVo.class);
        int articleFuzzyNum = articleMapper.getArticleFuzzyNum(title, summary);
        AdminArticlePageVo adminArticlePageVo = new AdminArticlePageVo(adminArticleVos, articleFuzzyNum);
        //获取文章
        return ResponseResult.okResult(adminArticlePageVo);
        
    }

    //根据id查询文章
    @Override
    public ResponseResult getArticleById(Long id) {
        Article article = articleMapper.selectById(id);
        AdminArticleAllVo adminArticleAllVo = BeanCopyUtils.copyBean(article, AdminArticleAllVo.class);
        List<Long> longs = articleTagMapper.selectTagList(id);
        adminArticleAllVo.setTags(longs);
        return ResponseResult.okResult(adminArticleAllVo);
    }

    //修改文章
    @Override
    public ResponseResult updateArticle(UpdateAdminArticleDto updateAdminArticleDto) {
        articleMapper.updateArticle(updateAdminArticleDto);

        List<Long> tags = updateAdminArticleDto.getTags();
        //删除标签
        articleTagMapper.deleteTagById(updateAdminArticleDto.getId());
        //添加标签
        for(Long tagId : tags){
            articleTagMapper.insert(updateAdminArticleDto.getId(), tagId);
        }
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult deleteArticle(Long[] ids) {
        articleMapper.deleteArticleById(ids);
        return ResponseResult.okResult();
    }
}
